package com.wang.common.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * 文件的工具类
 *
 * @author Wangsh
 */
public class FileUtil {
    /*匹配${}的正则,还有分组的概念*/
    private Pattern escapresource = Pattern.compile("(\\$\\{)([\\w]+)(\\})");

    /**
     * 读取一个文件内容
     *
     * @param is 文件的输入流
     * @return 文件的内容
     */
    public String readFile(InputStream is) {
        StringBuffer stringBuffer = new StringBuffer();
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String line = "";
            while ((line = bufferedReader.readLine()) != null) {
                /*System.out.println(line);*/
                stringBuffer.append(line + "\r\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }

    /**
     * 专门用来处理点位符
     *
     * @return
     */
    public String replaceOperator(String source, Map<String, String> paramsMap) {
        if (paramsMap.size() == 0) {
            return source;
        }

        StringBuffer sb = new StringBuffer();
        /*将${wangsh}的值替换掉*/
        Matcher matcher = this.escapresource.matcher(source);
        while (matcher.find()) {
            if (paramsMap.get(matcher.group(2)) != null) {
                matcher.appendReplacement(sb, paramsMap.get(matcher.group(2)));
            }
        }

        /* 将尾巴加上去 */
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 读取某个文件的内容
     * 并且为对象赋值,类似于资源文件
     * 如${wangsh},map中键为wangsh的值放的是yanglp,会将整个${wangsh}替换为yanglp
     *
     * @param sourceFile
     * @param charset
     * @param paramsMap  键为源文件中出现的,值为真正要替换的值
     * @return
     */
    public String readFile(InputStream is, String charset,
                           Map<String, String> paramsMap) {
        if (charset == null || "".equalsIgnoreCase(charset)) {
            charset = ConstatFinalUtil.CHARSET;
        }
        StringBuffer sb = new StringBuffer();
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(is, charset));
            String line = "";
            StringBuffer patressb = new StringBuffer();
            while ((line = br.readLine()) != null) {
                line = line.trim();
                patressb.append(line);
            }
            sb.append(this.replaceOperator(patressb.toString(), paramsMap));
            br.close();
        } catch (IOException e) {
            ConstatFinalUtil.SYS_LOGGER.error("读取文件出错了", e);
        }
        return sb.toString();
    }

    /**
     * 拷贝文件
     */
    public boolean copyFile(InputStream is, OutputStream os) {
        try {
            byte[] b = new byte[1024];
            int len = 0;
            while ((len = is.read(b)) != -1) {
                os.write(b, 0, len);
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            /* 一定要分开捕获 */
            try {
                if (os != null) {
                    os.close();
                    os = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (is != null) {
                    is.close();
                    is = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /* 拷贝失败了 */
        return false;
    }

    /**
     * 拷贝文件
     *
     * @param is        输入流
     * @param os        输出流
     * @param closeFlag 是否关闭流
     * @return 拷贝的结果
     */
    public boolean copyFile(InputStream is, OutputStream os, boolean closeFlag) {
        /* 拷贝的时候,带上粗管子 */
        BufferedInputStream bis = new BufferedInputStream(is);
        BufferedOutputStream bos = new BufferedOutputStream(os);

        /* 准备容器
         * 1024 * 1024 * 2 === 2m
         *  */
        byte[] b = new byte[2 * 1024 * 1024];
        int len = 0;
        try {
            while ((len = bis.read(b)) != -1) {
                bos.write(b, 0, len);
            }
            /* 写数据缓存 */
            bos.flush();
            /* 拷贝完成,返回true */
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (closeFlag) {
                try {
                    if (is != null) {
                        is.close();
                        is = null;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (os != null) {
                        os.close();
                        os = null;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 关闭流
     */
    public void closeStreamAll(InputStream is, OutputStream os) {
        try {
            if (is != null) {
                is.close();
                is = null;
            }
        } catch (IOException e) {
            ConstatFinalUtil.SYS_LOGGER.error("关闭is异常", e);
        }
        try {
            if (os != null) {
                os.close();
                os = null;
            }
        } catch (IOException e) {
            ConstatFinalUtil.SYS_LOGGER.error("关闭os异常", e);
        }
    }

    /**
     * 关闭流
     */
    public void closeCharAll(Reader reader, Writer writer) {
        try {
            if (reader != null) {
                reader.close();
                reader = null;
            }
        } catch (IOException e) {
            ConstatFinalUtil.SYS_LOGGER.error("关闭is异常", e);
        }
        try {
            if (writer != null) {
                writer.close();
                writer = null;
            }
        } catch (IOException e) {
            ConstatFinalUtil.SYS_LOGGER.error("关闭os异常", e);
        }
    }

    /**
     * 树形结构
     *
     * @param file 给定的目录或者文件
     * @return 返回一个容器, 里面放的是Map;<file对象,level层级,treeName树形结构的名字>
     */
    public List<Map<String, Object>> folderTree(File file, boolean deleteFlag) {
        List<Map<String, Object>> fileResList = new ArrayList<Map<String, Object>>();
        /* 递归 */
        folderTreeUtil(file, 0, fileResList, deleteFlag, file.getAbsolutePath());
        return fileResList;
    }

    /**
     * 主要是用来递归
     *
     * @param file
     * @param fileResList
     */
    private void folderTreeUtil(File file, int level, List<Map<String, Object>> fileResList, boolean deleteFlag, String parentAbsPath) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < level; i++) {
            sb.append(ConstatFinalUtil.SPLIT_STR);
        }
        //fileResList.add(file);
        Map<String, Object> fileMap = new HashMap<String, Object>();
        String fileAbsPath = file.getAbsolutePath();
        String fileRelaName = fileAbsPath.substring(fileAbsPath.indexOf(parentAbsPath) + parentAbsPath.length(), fileAbsPath.length());

        fileMap.put("file", file);
        fileMap.put("fileRelaName", fileRelaName);
        fileMap.put("level", level);
        fileMap.put("treeName", sb.toString() + file.getName());
        fileMap.put("fileSize", file.length());
        if (fileRelaName.lastIndexOf(".") != -1) {
            fileMap.put("extendName", fileRelaName.substring(fileRelaName.lastIndexOf(".") + 1, fileRelaName.length()));
        }

        if (file.isDirectory()) {
            /* 如果是目录的话,才会继续 */
            File[] listFiles = file.listFiles();
            for (File fileTemp : listFiles) {
                folderTreeUtil(fileTemp, level + 1, fileResList, deleteFlag, parentAbsPath);
            }
        }

        /* 删除文件 */
        if (deleteFlag) {
            boolean deleteFlagTemp = file.delete();
            fileMap.put("deleteFlag", deleteFlagTemp);
        }

        fileResList.add(fileMap);
    }

    /**
     * 压缩
     *
     * @param os         压缩文件的输出流
     * @param souFileMap 要压缩的文件列表;键为压缩包中文件的名字,值为:输入流(要压缩的文件)
     */
    public boolean zip(OutputStream os, Map<String, InputStream> souFileMap) {
        ZipOutputStream zos = new ZipOutputStream(os);
        try {
            /* 循环取出压缩文件列表 */
            for (Iterator<Entry<String, InputStream>> iterator = souFileMap.entrySet().iterator(); iterator.hasNext(); ) {
                Entry<String, InputStream> entry = iterator.next();
                String key = entry.getKey();
                InputStream souFileIs = entry.getValue();

                /* 压缩包里面的选项 */
                ZipEntry zipEntry = new ZipEntry(key);
                /* 将压缩包里面的内容放到压缩包中 */
                zos.putNextEntry(zipEntry);

                /* 拷贝文件 */
                this.copyFile(souFileIs, zos, false);
                /* 关闭文件 */
                souFileIs.close();
                /* 此文件结束 */
                zos.closeEntry();
                ConstatFinalUtil.SYS_LOGGER.info("==zip==name:{}=", key);
            }
            return true;
        } catch (FileNotFoundException e) {
            ConstatFinalUtil.SYS_LOGGER.error("文件木有找到;", e);
        } catch (Exception e) {
            ConstatFinalUtil.SYS_LOGGER.error("读取文件出错了", e);
        } finally {
            try {
                if (zos != null) {
                    zos.close();
                    zos = null;
                }
            } catch (IOException e) {
                ConstatFinalUtil.SYS_LOGGER.error("关闭zos出错了", e);
            }
        }
        return false;
    }

    /**
     * 解压缩
     *
     * @param is   压缩文件的位置
     * @param file 解压缩的目录
     */
    public boolean unzip(File souFile, File tarFile) {
        if (tarFile.exists() || tarFile.isFile()) {
            return false;
        }
        if (!tarFile.exists()) {
            tarFile.mkdirs();
        }
        /* 创建一个压缩文件 */
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(souFile);
            /**
             * 获取压缩文件的枚举项
             */
            Enumeration enu = zipFile.entries();
            while (enu.hasMoreElements()) {
                ZipEntry zipEntry = (ZipEntry) enu.nextElement();
                /* 压缩包中的文件对象 */
                File zipTempFile = new File(tarFile, zipEntry.getName());
                /* 判断是目录还是文件 */
                if (zipEntry.isDirectory()) {
                    /* 创建目录 */
                    zipTempFile.mkdirs();
                } else {
                    /* 只有一层目录的时候会有问题,会识别为文件 */
                    if (!zipTempFile.getParentFile().exists()) {
                        zipTempFile.getParentFile().mkdirs();
                    }
                    /* 文件 */
                    InputStream is = zipFile.getInputStream(zipEntry);
                    OutputStream os = new FileOutputStream(zipTempFile);
                    this.copyFile(is, os);
                }
            }
            return true;
        } catch (Exception e) {
            ConstatFinalUtil.SYS_LOGGER.error("读取文件出错了", e);
        } finally {
            try {
                if (zipFile != null) {
                    zipFile.close();
                    zipFile = null;
                }
            } catch (IOException e) {
                ConstatFinalUtil.SYS_LOGGER.error("关闭zos出错了", e);
            }
        }
        return false;
    }

    public static void main(String[] args) {
        FileUtil fileUtil = new FileUtil();
        String source = "abc${test}de${aa}fg";
        Map<String, String> paramsMap = new HashMap<String, String>();
        paramsMap.put("test", "测试一下");
        paramsMap.put("aa", "测试二下");
        String result = fileUtil.replaceOperator(source, paramsMap);
        System.out.println(result);
    }
}
